/*
 *  ShaderMain.cpp
 *  RTR
 *
 *  Created by Bernardo Franceschin on 4/21/11.
 *  Copyright 2011 PUC-Rio. All rights reserved.
 *
 */

#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include"glheader.h"
#include "image.h"                  /* TAD para imagem */
#include"lincontrol.h"

enum Alg{
  GAUSS ,
  MEDIAN ,
  SOBEL ,
  REDCOLOR ,
  GREY ,
  GAMMA ,
  HIST ,
  INV ,
  EMB,
  SAVEPIC,
  LAPSIMPLE,
  AND1,
  LAP,
  AND2,
  CANNY,
  STRETCH,
};

Image   *image1, *image2, *curr;
LinControl * lin;
bool undo = true;
bool stretch = false;
float gamma = 0.1;

void make_stretch ()
{
  float eq[6];
  int p1, p2;
  float curv[256];
  lin->GetXs(&p1,&p2);
  lin->GetEq(eq);
  int eq_id=0;
  for(int x=0;x<256;x++){
    if(x==p1)
      eq_id+=2;
    else if(x==p2)
      eq_id+=2;
    float xn = (float)x/255;
    curv[x] = eq[eq_id]*xn+eq[eq_id+1];
  }
  imgDestroy(image2);
  image2 = imgGrey(image1);
  imgApplyCurve(image2,curv);
}

void Keyboard(unsigned char key, int x, int y)
{
  Image * temp;
  int w = imgGetWidth(image2);
  int h = imgGetHeight(image2);
	switch ( key )
	{
    
    case 'r':
      imgDestroy(image2);
      image2 = imgCopy(image1);
      curr = image2;
      break;
    case 's':
      if(stretch)
        make_stretch();
      break;
    case '+':
      gamma += 0.1;
      printf("gamma=%f\n",gamma);
      break;
    case '-':
      gamma -= 0.1;
      printf("gamma=%f\n",gamma);
      break;
    case 'u':
      undo = !undo;
      curr = undo?image2:image1;
      break;
		case 27:
		case 'q':
		case 'Q':
			exit(0);
	}
  glutPostRedisplay();
}

void menuCallback (int id) 
{
  Image * temp;
  int w = imgGetWidth(image2);
  int h = imgGetHeight(image2);
  switch (id) {
    case GAUSS:
      temp = imgCopy(image2);
      imgGauss(image2,temp);
      curr = image2;
      imgDestroy(temp);
      break;
    case MEDIAN:
      imgMedian(image2);
      curr = image2;
      break;
    case SOBEL:
      temp = image2;
      image2=imgEdges(image2);
      curr = image2;
      imgDestroy(temp);
      break;
    case REDCOLOR:
      temp = image2;
      image2=imgReduceColors(image2,256);
      imgDestroy(temp);
      curr = image2;
      break;
    case GREY:
      temp = image2;
      image2 = imgGrey(image2);
      imgDestroy(temp);
      curr = image2;
      break;
    case GAMMA:
      imgGamma(image2,image1,gamma);
      curr = image2;
      break;
    case HIST:
      menuCallback(GREY);
      imgHistEq(image2);
      curr = image2;
      break;
    case INV:
      imgInvert(image2);
      curr = image2;
      break;
    //case EMB:
      //temp = imgCopy(image2);
      //imgEmb(image2,temp);
      //curr = image2;
      //imgDestroy(temp);
      //break;
    case SAVEPIC:
      imgWriteBMP(SAVE,image2);
      break;
    case LAPSIMPLE:
      temp = imgCopy(image2);
      imgLap(image2,temp);
      curr = image2;
      imgDestroy(temp);
      break;  
    case AND1:
      temp = imgCopy(image1);
      imgAnd(temp,image2);
      imgDestroy(image2);
      image2 = temp;
      curr = image2;
      break;
    case LAP:
      menuCallback(GAUSS);
      temp = imgCopy(image2);
      imgLap(image2,temp);
      imgDestroy(temp);
      temp = imgCopy(image1);
      imgSub(temp,image2);
      imgDestroy(image2);
      image2 = temp;
      curr = image2;
      break;
    case AND2:
      temp = imgAndBox (w,h, w/4, 3*w/4, h/4, 3*h/4);
      imgAnd(image2,temp);
      imgDestroy(temp);
      curr = image2;
      break;
    case CANNY:
      menuCallback(GAUSS);
      temp = imgCanny(image2, 0.04,0.5);
      imgDestroy(image2);
      image2 = temp;
      curr = image2;
      break;
    case STRETCH:
      stretch= !stretch;
      break;
  
  }
  glutPostRedisplay();
}

void mouse(int button, int state, int x, int y) 
{
  int h = imgGetHeight(image1);
  switch (button) {
    case GLUT_LEFT_BUTTON:
      if(state == GLUT_UP){
        lin->MouseLeftUp(x, h-y);
        if(stretch)
          Keyboard('s',0,0);
      }
      else
        lin->MouseLeftDown(x,h-y);
        glutPostRedisplay();
      break;
    default:
    break;
  }
}

void motion(int x,int y){
  //printf("MouseMotion= %d,%d %f,%f\n",x,y,translate_x(x),translate_y(y));
  int h = imgGetHeight(image1);
  if(lin->MouseMotion(x, h-y))
    glutPostRedisplay();
}

void Redraw ()
{
  int w = imgGetWidth(image1);
  int h = imgGetHeight(image1);
  int type = imgGetDimColorSpace(image1);
  float* rgbData = imgGetData(image1);
  //glRasterPos2i(w,0);
  if (!stretch){
    glWindowPos2i(0,0);
    if (type==3)
       glDrawPixels (w, h, GL_RGB,GL_FLOAT, rgbData);
    else if (type==1) 
       glDrawPixels (w, h, GL_LUMINANCE,GL_FLOAT, rgbData);
  }
  else{
    glClear(GL_COLOR_BUFFER_BIT);
    glViewport(0,0,w,h);
    lin->Draw();
  }
  type = imgGetDimColorSpace(image2);
  rgbData = imgGetData(image2);
  glWindowPos2i(w,0);
  if (type==3)
     glDrawPixels (w, h, GL_RGB,GL_FLOAT, rgbData);
  else if (type==1) 
     glDrawPixels (w, h, GL_LUMINANCE,GL_FLOAT, rgbData);
  glFlush();               /* forca atualizacao do OpenGL  (que pode ser bufferizado) */ 
}

int main (int argc, char** argv)
{
  image1 = imgReadBMP(LENA);
  //image1 = imgReadBMP(COLO);
  image2 = imgCopy(image1);
  curr = image2;
  int w=imgGetWidth(image1);
  int h=imgGetHeight(image1);
  lin = new LinControl(w,h);
  glutInit(&argc, argv);
  glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
  glutInitWindowSize(2*w,h);
  glutCreateWindow("ImageTest");
  glutDisplayFunc(Redraw);
  glutKeyboardFunc(Keyboard);
  glutMouseFunc(mouse);
  glutMotionFunc(motion);

  glutCreateMenu(menuCallback);
  glutAddMenuEntry("GAUSS", GAUSS);
  glutAddMenuEntry("MEDIAN",MEDIAN);
  glutAddMenuEntry("SOBEL",SOBEL);
  glutAddMenuEntry("REDCOLOR" ,REDCOLOR);
  glutAddMenuEntry("GREY" ,GREY);
  glutAddMenuEntry("GAMMA",GAMMA);
  glutAddMenuEntry("HIST",HIST);
  glutAddMenuEntry("INV" ,INV);
  //glutAddMenuEntry("EMB",EMB);
  glutAddMenuEntry("LAPSIMPLE",LAPSIMPLE);
  glutAddMenuEntry("LAP",LAP);
  //glutAddMenuEntry("AND1",AND1);
  glutAddMenuEntry("AND2",AND2);
  glutAddMenuEntry("CANNY",CANNY);
  glutAddMenuEntry("STRETCH",STRETCH);
  glutAddMenuEntry("SAVE",SAVEPIC);

  glutAttachMenu(GLUT_RIGHT_BUTTON);
  GLenum err = glewInit();
  if (GLEW_OK != err) { 
    fprintf(stderr, "GLEW Error: %s\n", glewGetErrorString(err));
    exit(-1);
  }

  glClearColor (1.0, 1.0, 1.0, 0.0);
  glLineWidth(2.0);
  

  glutMainLoop();
  return 0;
}
